﻿#ifndef ThreadWin32_h__2013_10_19__21_40
#define ThreadWin32_h__2013_10_19__21_40

#include <process.h>
#include "df.h"


namespace df
{
	//*******************************************
	// 以匿名表达式启动线程
	// 最好使用[=]按值传递(避免跨线程时引用到已释放的局部对象)
	//*******************************************
	class Thread
	{
	private:
		HANDLE handle_ = 0;

	public:
		Thread()
		{

		}
		~Thread(void)
		{
			::CloseHandle(handle_);
		}

		//*******************************************
		// Summary : 阻塞等待线程执行完成
		// Parameter - DWORD time : 等待超时值
		// Returns - bool : 成功与否(未超时)
		//*******************************************
		bool Wait(DWORD time = INFINITE, df::ErrWrap err = nullptr)
		{
			DWORD res = ::WaitForSingleObject(handle_, time);
			if (res == WAIT_FAILED)
			{
				DF_LASTERR(err, tcc_("Thread WaitForSingleObject failed!"));
				return false;
			}
			return (res == WAIT_OBJECT_0);
		}

		//*******************************************
		// Summary : 以匿名表达式启动线程,注意指针传递(避免跨线程时引用到已释放的局部对象)
		// Parameter - LambdaType & lam : 最好使用[=]按值传递,
		//*******************************************
		template<class LambdaType>
		inline static bool Start(LambdaType lam, df::ErrWrap err = nullptr)
		{
// 			std::thread thread(lam);
// 			thread.detach();
			auto res = StartThread(lam, err);
			if (res == 0)
				return false;
			::CloseHandle(res);
			return true;
		}

		template<class LambdaType>
		inline bool Run(LambdaType lam, df::ErrWrap err = nullptr)
		{
			handle_ = StartThread(lam, err);
			if (handle_ == 0)
				return false;
			return true;
		}

	private:
		template<class LambdaType>
		inline static HANDLE StartThread(const LambdaType & lam, df::ErrWrap err = nullptr)
		{
			LambdaType * lp = new LambdaType(lam);
			auto res = _beginthreadex(0, 0, RunThread<LambdaType>, lp, 0, 0);
			if (res == 0)
			{
				delete lp;
				DF_LASTERR(err, tcc_("_beginthreadex failed!"));
			}
			return (HANDLE)res;
		}

		template<class LambdaType>
		static unsigned int __stdcall RunThread(void *tp)
		{
			Exception::Instal();
			LambdaType * lp = (LambdaType *)tp;

			try
			{
				(*lp)();

			}DF_CATCH_ALL;

			delete lp;
			return 0;
		}

		DF_DISABLE_COPY_ASSIGN(Thread);
	};

}

#endif // ThreadWin32_h__2013_10_19__21_40
